/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/

#ifndef OSGTEXT_TEXT3D
#define OSGTEXT_TEXT3D 1


#include <osgText/TextBase>
#include <osgText/Font3D>


namespace osgText {


class OSGTEXT_EXPORT Text3D : public osgText::TextBase
{
public:

    /** Reder mode used to render the Text.
     * PER_FACE : render all front face with the default StateSet
     *                   all wall face with the wall StateSet
     *                   all back face with the back StateSet (back face of the character, no the OpenGL back face)
     *
     * PER_GLYPH : render all Charactere with the default StateSet
     */
    enum RenderMode
    {
        PER_FACE,
        PER_GLYPH
    };

    Text3D();
    Text3D(const Text3D& text,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY);

    META_Object(osgText,Text3D)

    /** Get the Charactere Depth of text. */
    float getCharacterDepth() const { return _characterDepth; }
    /** Set the Charactere Depth of text. */
    void setCharacterDepth(float characterDepth) { _characterDepth = characterDepth; computeGlyphRepresentation(); }

    /** Get the render mode used to render the text. */
    RenderMode getRenderMode() const { return _renderMode; }
    /** Set the render mode used to render the text. */
    void setRenderMode(RenderMode renderMode) { _renderMode = renderMode; computeGlyphRepresentation(); }

//    /** Get the wall StateSet */
//    osg::StateSet * getWallStateSet() { return _wallStateSet.get(); }
//    /** Get or create the wall StateSet */
//    osg::StateSet * getOrCreateWallStateSet()
//    {
//        if (_wallStateSet.valid() == false) _wallStateSet = new osg::StateSet;
//        return _wallStateSet.get();
//    }
//    /** Set the wall StateSet */
//    void setWallStateSet(osg::StateSet * wallStateSet)  { _wallStateSet = wallStateSet; }
//
//    /** Get the back StateSet */
//    osg::StateSet * getBackStateSet() { return _backStateSet.get(); }
//    /** Get or create the back StateSet */
//    osg::StateSet * getOrCreateBackStateSet() { if (_backStateSet.valid() == false) _backStateSet = new osg::StateSet; return _backStateSet.get(); }
//    /** Set the back StateSet */
//    void setBackStateSet(osg::StateSet * backStateSet)  { _backStateSet = backStateSet; }
//

    /** Set the Font to use to render the text.
      * setFont(0) sets the use of the default font.*/
    inline void setFont(Font3D* font=0) { setFont(osg::ref_ptr<Font3D>(font)); };

    /** Set the Font to use to render the text.*/
    void setFont(osg::ref_ptr<Font3D> font);


    /** Set the font, loaded from the specified front file, to use to render the text,
      * setFont("") sets the use of the default font.
      * See the osgText::readFontFile function for how the font file will be located. */
    void setFont(const std::string& fontfile);

    /** Get the font. Return 0 if default is being used.*/
    const Font3D* getFont() const { return _font.get(); }




    /** Draw the text.*/
    virtual void drawImplementation(osg::RenderInfo& renderInfo) const;

    /** return false, osgText::Text does not support accept(AttributeFunctor&).*/
    virtual bool supports(const osg::Drawable::AttributeFunctor&) const { return false; }

    /** return true, osgText::Text does support accept(ConstAttributeFunctor&).*/
    virtual bool supports(const osg::Drawable::ConstAttributeFunctor&) const { return false; }

    /** accept an ConstAttributeFunctor and call its methods to tell it about the interal attributes that this Drawable has.*/
    virtual void accept(osg::Drawable::ConstAttributeFunctor& af) const;

    /** return true, osgText::Text does support accept(PrimitiveFunctor&) .*/
    virtual bool supports(const osg::PrimitiveFunctor&) const { return false; }

    /** accept a PrimtiveFunctor and call its methods to tell it about the interal primtives that this Drawable has.*/
    virtual void accept(osg::PrimitiveFunctor& pf) const;


    /** Set whether to use a mutex to ensure ref() and unref() are thread safe.*/
    virtual void setThreadSafeRefUnref(bool threadSafe);

    /** Resize any per context GLObject buffers to specified size. */
    virtual void resizeGLObjectBuffers(unsigned int maxSize);

    /** If State is non-zero, this function releases OpenGL objects for
      * the specified graphics context. Otherwise, releases OpenGL objexts
      * for all graphics contexts. */
    virtual void releaseGLObjects(osg::State* state=0) const;

//    // make Font a friend to allow it set the _font to 0 if the font is
//    // forcefully unloaded.
    friend class Font3D;

    virtual osg::BoundingBox computeBound() const;


protected:

    virtual ~Text3D() {}

    void renderPerGlyph(osg::State & state) const;
    void renderPerFace(osg::State & state) const;

    String::iterator computeLastCharacterOnLine(osg::Vec2& cursor, String::iterator first,String::iterator last);

    void computeGlyphRepresentation();
    void computePositions(unsigned int contextID) const;

    // ** glyph and other information to render the glyph
    struct GlyphRenderInfo
    {
        GlyphRenderInfo(Font3D::Glyph3D * glyph, osg::Vec3 & pos) :
            _glyph(glyph), _position(pos) {}

        osg::ref_ptr<Font3D::Glyph3D> _glyph;
        osg::Vec3 _position;
    };

    typedef std::vector<GlyphRenderInfo> LineRenderInfo;
    typedef std::vector<LineRenderInfo> TextRenderInfo;

    TextRenderInfo _textRenderInfo;

    osg::ref_ptr<Font3D> _font;

    float _characterDepth;

    RenderMode _renderMode;

    osg::ref_ptr<osg::StateSet> _wallStateSet;
    osg::ref_ptr<osg::StateSet> _backStateSet;
};

}


#endif
